﻿using Castle.Core.Configuration;
using Castle.Core.Configuration.Xml;
using System;
using System.IO;
using System.Linq;
using System.Xml;

namespace Inovout.Runtime
{
    public class ApplicationWrapper : IDisposable
    {
        public DynamicDictionary Settings { get; private set; }
        private string title;
        public string Title
        {
            get { return title; }
        }
        private IApplication application;
        public ApplicationWrapper(IApplication application)
        {
            ArgumentAssert.IsNotNull(application, "application");
            this.application = application;
        }
        public void Initialize()
        {
            InitializeFromProductConfig();
            ComponentRegistry.Initialize(application);
        }
        public void Dispose()
        {
            ComponentRegistry.Clear();
        }
        private IConfiguration configuration;
        public IConfiguration Configuration
        {
            get { return configuration ?? new MutableConfiguration("product"); }
        }
        private void ReadProdcutConfig(string productConfigFilePath)
        {
            using (FileStream productConfigStream = new FileStream(productConfigFilePath, FileMode.Open, FileAccess.Read))
            {
                ReadProdcutConfig(productConfigStream);
            }
        }
        public IConfiguration ProductConfiguration { get; private set; }
        private void ReadProdcutConfig(Stream productConfigStream)
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(productConfigStream);
            ProductConfiguration = XmlConfigurationDeserializer.GetDeserializedNode(xmlDocument.DocumentElement);
            configuration = ProductConfiguration.Children[0].Children.Single(c => c.Attributes["name"].Equals(application.Name));
            title = configuration.Attributes["title"];
            IConfiguration settingsConfiguration = ProductConfiguration.Children.SingleOrDefault(c => c.Name.Equals("settings"));
            if (settingsConfiguration != null)
            {
                //todo:合并Application自身的Settings
                configuration.Children.Add(settingsConfiguration);

            }
            var settingDictionary = settingsConfiguration.Children.Select(nv =>
                 new { Key = nv.Attributes["name"], Value = nv.Attributes["value"] })
                 .ToDictionary(p => p.Key, p => p.Value);
            Settings = new DynamicDictionary(() => settingDictionary);
            IConfiguration dataSourceConfiguration = configuration.Children.SingleOrDefault(c => c.Name.Equals("dataSource"));
            if (dataSourceConfiguration == null)
            {
                dataSourceConfiguration = new MutableConfiguration("dataSource");
                configuration.Children.Add(dataSourceConfiguration);
            }
            IConfiguration databasesConfiguration = configuration.Children.SingleOrDefault(c => c.Name.Equals("databases"));
            IConfiguration repositoriesConfiguration = configuration.Children.SingleOrDefault(c => c.Name.Equals("repositories"));
            if (databasesConfiguration == null)
            {
                databasesConfiguration = new MutableConfiguration("databases");
                dataSourceConfiguration.Children.Add(databasesConfiguration);
                IConfiguration productDatabasesConfiguration = ProductConfiguration.Children.SingleOrDefault(c => c.Name.Equals("databases"));
                foreach (IConfiguration repositoryConfiguration in repositoriesConfiguration.Children)
                {
                    databasesConfiguration.Children.Add(productDatabasesConfiguration.Children.Single(c => c.Attributes["name"].Equals(repositoryConfiguration.Attributes["databaseName"])));
                }
            }
            dataSourceConfiguration.Children.Add(repositoriesConfiguration);
        }
        protected virtual void InitializeFromProductConfig()
        {
            string productConfigFilePath = Path.Combine(application.Path, @"Configs\Product.config");
            if (File.Exists(productConfigFilePath))
            {
                ReadProdcutConfig(productConfigFilePath);
            }
            else
            {
                productConfigFilePath = Path.Combine(application.Path, @"..\Product.config");
                if (File.Exists(productConfigFilePath))
                {
                    ReadProdcutConfig(productConfigFilePath);

                }
            }
        }
    }
}
